package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.config.VodConstantProperties;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.UploadFileUtil;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.*;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.xiaoymin.knife4j.core.util.Assert;
import com.qcloud.vod.VodUploadClient;
import com.qcloud.vod.model.VodUploadRequest;
import com.qcloud.vod.model.VodUploadResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

	@Autowired
	private TrackInfoMapper trackInfoMapper;

	@Autowired
	private VodConstantProperties vodConstantProperties;

	@Autowired
	private TrackStatMapper trackStatMapper;

	@Autowired
	private AlbumInfoMapper albumInfoMapper;

	@Autowired
	private VodService vodService;

	@Autowired
	private UserInfoFeignClient userInfoFeignClient;

	@Autowired
	private AlbumStatMapper albumStatMapper;

	/**
	 * @author WeakMoon
	 * @date 2025/03/09 16:08:06
	 * 批量获取下单付费声音列表
	 */
	@Override
	public List<TrackInfo> findPaidTrackInfoList(Long trackId, Integer trackCount, Long userId) {
		//声明一个集合
		List<TrackInfo> trackInfoList = new ArrayList<>();

		//通过声音id获取声音对象
		TrackInfo trackInfo= trackInfoMapper.selectById(trackId);

		//获取用户购买过的集合
		Result<List<Long>> userPaidTrackList = userInfoFeignClient.findUserPaidTrackList(trackInfo.getAlbumId());
		Assert.notNull(userPaidTrackList,"远程调用获取用户购买的声音id失败");
		//获取已购买的声音id
		List<Long> trackIdPaidList = userPaidTrackList.getData();

		if (trackCount > 0){
			//多集声音
			//select * from track_info where id > 18031 and track_info.album_id = ? and id not in(18034,18035) limit 10;
			LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<>();
			wrapper.gt(TrackInfo::getId,trackId).eq(TrackInfo::getAlbumId,trackInfo.getAlbumId());
			if (trackIdPaidList.size() > 0){
				//排除已购买的声音id
				wrapper.notIn(TrackInfo::getId,trackIdPaidList);
			}
			wrapper.last("limit " + trackCount);

			//获取集合数据
			trackInfoList = trackInfoMapper.selectList(wrapper);
		}else {
			//若等于0，就是本集
			//判断本集是否购买过
			if (trackIdPaidList.contains(trackId)){
				return new ArrayList<>();
			}
			trackInfoList.add(trackInfo);
		}

		//返回结果数据
		return trackInfoList;
	}

	/**
	 * @author WeakMoon
	 * @date 2025/03/08 16:16:45
	 * 声音分集列表
	 */
	@Override
	public List<Map<String, Object>> findUserTrackPaidList(Long trackId, Long userId) {
		TrackInfo trackInfo = this.getById(trackId);
		AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfo.getAlbumId());
		LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<>();
		wrapper.eq(TrackInfo::getAlbumId,trackInfo.getAlbumId()).gt(TrackInfo::getOrderNum,trackInfo.getOrderNum());
		List<TrackInfo> trackInfoList = trackInfoMapper.selectList(wrapper);

		Result<List<Long>> trackIdListResult = userInfoFeignClient.findUserPaidTrackList(trackInfo.getAlbumId());
		Assert.notNull(trackIdListResult,"远程调用获取用户购买过的声音id失败");
		List<Long> trackIdList = trackIdListResult.getData();
		Assert.notNull(trackIdList,"远程调用用户购买声音id失败");

		List<TrackInfo> infoList = trackInfoList.stream().filter(trackInfo1 -> !trackIdList.contains(trackInfo1.getId())).collect(Collectors.toList());
		List<Map<String, Object>> list = new ArrayList<>();
		if (infoList.size() >= 0){
			//构建本集操作
			HashMap<String, Object> map = new HashMap<>();
			map.put("name","本集");
			map.put("price",albumInfo.getPrice());
			map.put("trackCount",0);
			list.add(map);
		}
		if (infoList.size() > 0 && infoList.size() <= 10){
			HashMap<String, Object> map = new HashMap<>();
			int count = infoList.size();
			map.put("name","后" + count + "集");
			map.put("price",albumInfo.getPrice().multiply(new BigDecimal(String.valueOf(count))));
			map.put("trackCount",count);
			list.add(map);
		}
		if (infoList.size() > 10){
			HashMap<String, Object> map = new HashMap<>();
			map.put("name","后10集");
			map.put("price",albumInfo.getPrice().multiply(new BigDecimal("10")));
			map.put("trackCount",10);
			list.add(map);
		}
		if (infoList.size() > 10 && infoList.size() <= 20) {
			Map<String, Object> map = new HashMap<>();
			int count = infoList.size();
			map.put("name", "后" + count + "集");
			map.put("price", albumInfo.getPrice().multiply(new BigDecimal(String.valueOf(count))));
			map.put("trackCount", count);
			list.add(map);
		}
		if (infoList.size() > 20) {
			Map<String, Object> map = new HashMap<>();
			map.put("name", "后20集");
			map.put("price", albumInfo.getPrice().multiply(new BigDecimal(String.valueOf("20"))));
			map.put("trackCount", 20);
			list.add(map);
		}
		if (infoList.size() > 30 && infoList.size() <= 40) {
			Map<String, Object> map = new HashMap<>();
			int count = infoList.size();
			map.put("name", "后" + count + "集");
			map.put("price", albumInfo.getPrice().multiply(new BigDecimal(String.valueOf(count))));
			map.put("trackCount", count);
			list.add(map);
		}
		if (infoList.size() > 30) {
			Map<String, Object> map = new HashMap<>();
			map.put("name", "后30集");
			map.put("price", albumInfo.getPrice().multiply(new BigDecimal(String.valueOf("30"))));
			map.put("trackCount", 30);
			list.add(map);
		}
		return list;
	}

	/**
	 * @author WeakMoon
	 * @date 2025/03/03 16:18:03
	 * 根据专辑id获取声音列表
	 */
	@Override
	public IPage<AlbumTrackListVo> findAlbumTrackPage(Page<AlbumTrackListVo> trackListVoPage, Long albumId, Long userId) {
		//  跟用户专辑类型有关系！ 根据用户的身份！ 根免费试听集数有关系!
		//  1.  先查询有多少条声音;
		IPage<AlbumTrackListVo> pageInfo = trackInfoMapper.selectAlbumTrackPage(trackListVoPage, albumId);
		//  根据专辑Id获取专辑对象;
		AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
		//  2.  判断这个用户id 是否为空
		if (null == userId) {
			//  说明未登录; 需要判断专辑的类型; 除免费专辑之外，都需要将声音Id 设置为付费(除试听集数 album_info.tracks_for_free);
			if (!SystemConstant.ALBUM_PAY_TYPE_FREE.equals(albumInfo.getPayType())) {
				//  order_num > album_info.tracks_for_free; 需要将这些数据的字段  isShowPaidMark = true;
				//                for (AlbumTrackListVo albumTrackListVo : pageInfo.getRecords()) {
				//                    if (albumTrackListVo.getOrderNum() > albumInfo.getTracksForFree()){
				//                        albumTrackListVo.setIsShowPaidMark(true);
				//                    }
				//                }
				pageInfo.getRecords().stream().filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > albumInfo.getTracksForFree()).forEach(albumTrackListVo -> albumTrackListVo.setIsShowPaidMark(true));
			}
			//  返回数据;
			return pageInfo;
		}
		//  用户Id 不为空
		if (null != userId) {
			//  声明一个变量 是否需要付费;
			boolean isNeedPay = false;
			//  登录了！ 判断专辑类型: vip 免费； 付费;
			if (SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(albumInfo.getPayType())) {
				//  vip 免费 -- 判断用户身份:
				Result<UserInfoVo> infoVoResult = userInfoFeignClient.getUserInfo(userId);
				com.github.xiaoymin.knife4j.core.util.Assert.notNull(infoVoResult, "远程调用获取用户信息失败");
				UserInfoVo userInfoVo = infoVoResult.getData();
				com.github.xiaoymin.knife4j.core.util.Assert.notNull(userInfoVo, "远程调用获取用户信息失败");
				if (0 == userInfoVo.getIsVip() || (1 == userInfoVo.getIsVip() && userInfoVo.getVipExpireTime().before(new Date()))) {
					//  付费;
					isNeedPay = true;
				}
			} else if (SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(albumInfo.getPayType())) {
				//  付费;
				isNeedPay = true;
			}
			//  判断付费情况
			if (isNeedPay) {
				//  当前专辑的哪些声音Id 需要付费！ 6-25; 除去免费试听集数;  (判断这个用户是否购买过专辑或购买过单集声音)
				List<AlbumTrackListVo> albumTrackListPaidList = pageInfo.getRecords().stream().filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > albumInfo.getTracksForFree()).collect(Collectors.toList());
				//  需要付费的声音Id;
				List<Long> trackNeedPaidList = albumTrackListPaidList.stream().map(AlbumTrackListVo::getTrackId).collect(Collectors.toList());
				//  远程调用: map.put(trackId,1); map.put(trackId,0); 1:表示已经购买; 0:表示未购买 setIsShowPaidMark(true);
				Result<Map<Long, Integer>> mapResult = userInfoFeignClient.userIsPaidTrack(albumId,trackNeedPaidList);
				Assert.notNull(mapResult, "远程调用获取用户付费情况失败");
				//  map.put(trackId,1); map.put(trackId,0); 1:表示已经购买; 0:表示未购买 setIsShowPaidMark(true);
				Map<Long, Integer> map = mapResult.getData();
				//  循环遍历集合;
				for (AlbumTrackListVo albumTrackListVo : albumTrackListPaidList) {
					//  boolean flag = map.get(albumTrackListVo.getTrackId()) == 0?true:false;
					//  true; false;
					albumTrackListVo.setIsShowPaidMark(map.get(albumTrackListVo.getTrackId()) == 0);
				}
			}
		}
		//  返回数据
		return pageInfo;
	}

	/**
	 * @author WeakMoon
	 * @date 2025/03/04 20:09:51
	 * 修改声音统计
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateTrackStat(TrackStatMqVo trackStatMqVo) {
	    // 更新声音统计信息
	    try {
	        trackStatMapper.updateTrackStat(trackStatMqVo.getCount(),trackStatMqVo.getTrackId(),trackStatMqVo.getStatType());
	        // 如果统计类型为播放量，则同时更新专辑的播放统计信息
	        if (SystemConstant.TRACK_STAT_PLAY.equals(trackStatMqVo.getStatType())){
	            albumStatMapper.updateAlbumStat(trackStatMqVo.getCount(),trackStatMqVo.getAlbumId(),SystemConstant.ALBUM_STAT_PLAY);
	        }
	    } catch (Exception e) {
	        // 捕获异常并抛出运行时异常
	        throw new RuntimeException(e);
	    }
	}

	/**
	 * @author WeakMoon
	 * @date 2025/02/23 18:08:04
	 * 修改声音信息
	 */
	@Override
	public void updateTrackInfo(Long trackId, TrackInfoVo trackInfoVo) {
	    // 根据声音ID获取声音信息
	    TrackInfo trackInfo = this.getById(trackId);

	    // 保存原始媒体文件ID
	    String oldMediaFileId = trackInfo.getMediaFileId();

	    // 将传入的声音信息复制到声音对象中
	    BeanUtils.copyProperties(trackInfoVo,trackInfo);

	    // 获取新的媒体文件ID
	    String mediaFileId = trackInfoVo.getMediaFileId();

	    // 检查媒体文件ID是否发生变化
	    if (!oldMediaFileId.equals(mediaFileId)){

	        // 如果媒体文件ID发生变化，获取新的媒体信息
	        TrackMediaInfoVo mediaInfo = vodService.getMediaInfo(mediaFileId);

	        // 更新声音信息中的媒体时长
	        trackInfo.setMediaDuration(mediaInfo.getDuration());

	        // 更新声音信息中的媒体类型
	        trackInfo.setMediaType(mediaInfo.getType());

	        // 更新声音信息中的媒体大小
	        trackInfo.setMediaSize(mediaInfo.getSize());

	        // 更新声音信息中的媒体URL
	        trackInfo.setMediaUrl(mediaInfo.getMediaUrl());

	        // 删除旧的媒体文件
	        vodService.deleteMedia(oldMediaFileId);
	    }
	    // 更新数据库中的声音信息
	    trackInfoMapper.updateById(trackInfo);
	}

	/**
	 * @author WeakMoon
	 * @date 2025/02/23 15:32:00
	 * 根据声音id，删除声音对象
	 * 这个方法执行以下几个步骤来完成声音对象的删除：
	 * 1. 首先通过ID查询声音信息（TrackInfo）。
	 * 2. 删除声音信息记录。
	 * 3. 删除与该声音相关的统计信息（TrackStat）。
	 * 4. 从所属专辑中减去声音计数。
	 * 5. 更新专辑中剩余声音的排序编号。
	 * 6. 调用视频服务删除与声音关联的媒体文件。
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void removeTrackInfo(Long trackId) {
	    // 查询声音信息
	    TrackInfo trackInfo = trackInfoMapper.selectById(trackId);

	    // 删除声音信息记录
	    trackInfoMapper.deleteById(trackId);

	    // 删除与该声音相关的所有统计信息
	    trackStatMapper.delete(new LambdaQueryWrapper<TrackStat>().eq(TrackStat::getTrackId,trackId));

	    // 查询所属专辑信息
	    AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfo.getAlbumId());

	    // 更新专辑的声音计数，减去1
	    albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() - 1);
	    albumInfoMapper.updateById(albumInfo);

	    // 更新专辑中剩余声音的排序编号
	    trackInfoMapper.updateOrderNum(albumInfo.getId(),trackInfo.getOrderNum());

	    // 调用视频服务删除与声音关联的媒体文件
	    vodService.deleteMedia(trackInfo.getMediaFileId());
	}

	/**
	 * @author WeakMoon
	 * @date 2025/02/23 14:12:41
	 * 根据用户Id，状态等条件查询声音列表
	 */
	@Override
	public IPage<TrackListVo> findUserTrackPage(Page<TrackListVo> trackListVoPage, TrackInfoQuery trackInfoQuery) {
		return trackInfoMapper.selectUserTrackPage(trackListVoPage,trackInfoQuery);
	}

	/**
	 * @author WeakMoon
	 * @date 2025/02/22 17:18:02
	 * 保存声音
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void saveTrackInfo(TrackInfoVo trackInfoVo, Long userId) {
	    // 创建一个新的TrackInfo对象，并从传入的TrackInfoVo对象中复制属性
	    TrackInfo trackInfo = new TrackInfo();
	    BeanUtils.copyProperties(trackInfoVo,trackInfo);

	    // 设置声音的用户ID
	    trackInfo.setUserId(userId);

	    // 根据专辑ID查询专辑信息
	    AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfoVo.getAlbumId());
	    // 设置声音在专辑中的顺序号，为当前专辑包含的声音数量加1
	    trackInfo.setOrderNum(albumInfo.getIncludeTrackCount() + 1);

	    // 调用视频服务，获取声音的媒体信息
	    TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(trackInfoVo.getMediaFileId());


	    // 设置声音的媒体大小
	    trackInfo.setMediaSize(trackMediaInfoVo.getSize());

	    // 设置声音的媒体时长
	    trackInfo.setMediaDuration(trackMediaInfoVo.getDuration());

	    // 设置声音的媒体URL
	    trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());

	    // 设置声音的媒体类型
	    trackInfo.setMediaType(trackMediaInfoVo.getType());

	    // 插入声音信息到数据库
	    trackInfoMapper.insert(trackInfo);

	    // 保存声音的播放、收藏、点赞、评论统计信息
	    this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PLAY);
	    this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COLLECT);
	    this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PRAISE);
	    this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COMMENT);

	    // 更新专辑信息，增加包含的声音数量
	    albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() + 1);
	    albumInfoMapper.updateById(albumInfo);
	}

	/**
	 * 保存声音的统计信息
	 * @param trackId 声音ID
	 * @param StatPlay 统计类型
	 */
	private void saveTrackStat(Long trackId, String StatPlay) {
	    // 创建一个新的TrackStat对象
	    TrackStat trackStat = new TrackStat();

	    // 设置声音ID
	    trackStat.setTrackId(trackId);

	    // 设置统计类型
	    trackStat.setStatType(StatPlay);

	    // 设置统计数值，为一个随机数
	    trackStat.setStatNum(new Random().nextInt(10000000));

	    // 插入统计信息到数据库
	    trackStatMapper.insert(trackStat);
	}

	/**
	 * @author WeakMoon
	 * @date 2025/02/22 15:51:50
	 * 上传声音
	 */
	@Override
	public Map<String, Object> uploadTrack(MultipartFile file) {
		// 创建Vod上传客户端实例
		VodUploadClient client = new VodUploadClient(vodConstantProperties.getSecretId(), vodConstantProperties.getSecretKey());

		// 初始化上传请求对象
		VodUploadRequest request = new VodUploadRequest();

		// 执行文件上传到临时路径，并获取上传后的文件路径
		String path = UploadFileUtil.uploadTempPath(vodConstantProperties.getTempPath(),file);

		// 设置上传请求的媒体文件路径
		request.setMediaFilePath(path);

		try {
			// 执行文件上传，并获取上传响应
			VodUploadResponse response = client.upload(vodConstantProperties.getRegion(), request);

			// 记录上传成功的文件ID
			log.info("Upload FileId = {}", response.getFileId());

			// 创建一个HashMap来存储上传成功后的信息
			HashMap<String, Object> map = new HashMap<>();

			// 将文件ID和封面URL存入map中
			map.put("mediaFileId",response.getFileId());
			map.put("mediaUrl",response.getMediaUrl());

			// 返回包含文件ID和封面URL的map
			return map;

		} catch (Exception e) {
			// 业务方进行异常处理
			log.error("Upload Err", e);
		}

		// 如果上传失败，返回一个空的Map
		return Map.of();
	}



}
